
<template>
    <div class="_container" :class="{active:props.id==activeNodeId}" @mousedown.capture="updateActiveNode(props.id)">
        <!-- 标题栏 -->
        <div class="fx fx-c_center pad-16 header">
            <div class="fx fx-center wh-40 logo">
                <jb-icon :local="true" :icon="nodeDef.icon" width="30" :color="nodeDef.group.activeColor"></jb-icon>
            </div>
            <div class="ml-10 tc-dark flex-1">
                <div v-if="!isEditingName">
                    {{ nodeName}}
                    <jb-icon v-if="props.id==activeNodeId" @click="editName" class="cursor-pointer inline-block align-[-3px] " width="16px" :local="true" icon="ant-design:edit-filled" color="#999"></jb-icon></div>
                <div v-if="isEditingName"  class="flex items-center" @mousedown.stop>
                    <n-input style="width:200px" v-model:value="newName" @keydown.enter="applyNewName"></n-input>
                    <jb-btn @click="applyNewName"  quaternary circle  type="success" icon="iconamoon:check-duotone"></jb-btn>
                    <jb-btn @click="isEditingName=false" quaternary circle  type="error" icon="line-md:cancel"></jb-btn>
                </div>
                <p class="font-12 tc-assist">{{nodeDef.desc}}</p>
            </div>

        </div>

        <div class="tools_panel" v-if="props.id==activeNodeId">
            <jb-btn confirmText="确认删除该节点吗？" @confirm="removeNode(props.id)"  size="small" type="error" icon="fluent:delete-28-filled" >删除</jb-btn>
        </div>

        <!-- 主区域 -->
        <div class="form fx-col pad-16 " @mousedown.stop>
            <slot></slot>
        </div>

        <Handle type="target" :position="Position.Left">
        </Handle>

        <!-- 触发器 -->
        <n-popover trigger="hover">
            <template #trigger>
                <n-popselect v-model:value="props.config.triggerConfig.triggerType" :options="triggerOptions" trigger="click">
                    <jb-icon :local="true" :icon="`jb:branch-${props.config.triggerConfig.triggerType}`" class="trigger_btn" width="20px"></jb-icon>
                </n-popselect>

            </template>
            <span>{{props.config.triggerConfig.triggerType=='ANY'?'任意':'所有'}}前置节点结束后触发</span>
        </n-popover>
        <div>
            <slot name="source"></slot>
        </div>
        <div class="footer pad-16">
            <slot name="footer"></slot>
        </div>
    </div>
</template>

<script setup>

import {getNodeByType, getNodeOutputFieldNames} from "@/views/app/chain/nodes/node-def.js";
import {computed, inject, onMounted, provide, ref, watch} from "vue";
import {Handle, Position, useVueFlow} from "@vue-flow/core";

const props = defineProps({
    id: {
        type: String,
        required: true
    },
    config: {
        type: Object,
        required: true
    },
    type: {
        type: String,
        required: true
    },

})

if (!props.config.triggerConfig) {
    props.config.triggerConfig = {
        triggerType: 'ALL_OVER',
    }
}

const nodeDef = ref(getNodeByType(props.type))

const triggerOptions = [
    {label:"所有前置节点结束后触发", value:'ALL_OVER'},
    {label:"任意前置节点结束后触发", value:'ANY'},
]


/** 监听config的变化，自动触发更新 */
const updateNodesData = inject("updateNodesData")

watch(() => props.config, (newValue, oldValue) => {
    console.debug('配置发生变化 ', newValue);
    updateNodesData();
}, {
    deep: true
})



/** 获取所有前置节点的输出字段，并生成下拉选项 */
const flow = useVueFlow();

const prevOutputFieldOptions = ref([])
const initDone = ref(false);

defineExpose({
    prevOutputFieldOptions,
    initDone
})


onMounted(() => {
    setTimeout(() => {
        updatePrevOutputFieldOptions(props.id);
        initDone.value =true;
    }, 110)
});


// watch(() => flow.getEdges.value, (newV) => {
//     console.debug("监听到edge改动", newV)
//     updatePrevOutputFieldOptions(props.id);
// })


flow.onEdgesChange(events => {
    if (events.some(item => item.type === 'remove' || item.type === 'add')) {
        console.debug("监听到edge变动，更新前置节点输出字段options")
        prevOutputFieldOptions.value = [];
        updatePrevOutputFieldOptions(props.id);
    }
})

function updatePrevOutputFieldOptions(sourceNodeId) {
    console.debug("更新前置节点的输出字段选项", prevOutputFieldOptions.value)
    const connections = flow.getConnectedEdges(sourceNodeId).filter(edge => edge.targetNode.id == sourceNodeId);
    // 遍历所有前置连接
    connections.forEach(connection => {
        const sourceNode = connection.sourceNode;
        if (sourceNode) {
            // 获取该类型节点的所有输出字段名称
            const outputFields = getNodeOutputFieldNames(sourceNode.type);

            // 从sourceNode.data中获取对应字段的值
            outputFields.forEach(fieldPath => {
                // 处理嵌套字段路径，如 "llmConfig.outputField"
                const value = fieldPath.split('.').reduce((obj, key) => obj && obj[key], sourceNode
                    .data);
                if (value) {
                    if (prevOutputFieldOptions.value.some(item => item.value === value) == false) {
                        prevOutputFieldOptions.value.push({
                            label: value,
                            value: value
                        });
                    }
                }
            });
            updatePrevOutputFieldOptions(connection.source)

        }
    });

}

/**==============激活相关代码 =========================== **/

const activeNodeId = inject("activeNodeId")
const updateActiveNode = inject("updateActiveNode")


/**==============节点操作相关代码 =========================== **/

const removeNode = inject("removeNode")

const isEditingName = ref(false);
const newName =ref('');
const nodeName = computed(() => {
    return props.config?._nodeConfig?.name ||  nodeDef.value.name;
})
function editName() {
    newName.value = props.config?._nodeConfig?.name ||  nodeDef.value.name;
    isEditingName.value = true;
}

/**
 * 应用新的名字
 */
function applyNewName() {
    if (!props.config._nodeConfig) {
        props.config._nodeConfig = {};
    }
    props.config._nodeConfig.name= newName.value;
    isEditingName.value = false;
}



</script>

<style scoped>

._container {
    position: relative;
    /* 确保父容器有定位属性 */
    background-color: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 12px;
    box-sizing: border-box;
    width: 500px;
    box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0.1) 0px 10px 15px -3px, rgba(0, 0, 0, 0.1) 0px 4px 6px -4px;
}

._container.active {
    border: 2px solid #7baaf8; /* 蓝色边框，更粗 */
    transform: scale(1.05); /* 轻微放大 */
    transition: all 0.2s ease; /* 平滑过渡效果 */
    box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(167, 209, 235, 0.78) 0px 5px 15px -3px, rgba(82, 169, 254, 0.71) 0px 0px 6px -4px;
}

.tools_panel {
    position: absolute;
    height: 35px;
    width: 100%;
    display: flex;
    justify-content: flex-end;
    align-items: center;
    right: 0;
    top: -40px;
}

.header,
.form {
    border-bottom: 1px solid rgb(229, 231, 235);
}
.logo {
    background: v-bind(nodeDef.group.bgColor);
    border-radius: 12px;
}

.trigger_btn {
    position: absolute;
    left: 0%;
    top: 50%;
    transform: translate(-50%, -50%);
    z-index: 2;
    color: rgba(88, 34, 217, 0.5);
    cursor: pointer;
}
.trigger_btn:hover{
    color: rgba(88, 34, 217,1);
}
.trigger_btn:focus{
    outline: none;
}

.footer {
    display: none;
}
.footer:has(*) {
    display: block;
}
</style>